/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file    ymodem.c
 * @brief   This file provides code for the configuration
 *          of the YMODEM protocol.
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2025 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "ymodem.h"
#include "main.h"
#include "usart.h"
#include "stdlib.h"

/* USER CODE BEGIN 0 */
/* YMODEM包类型定义 */
uint8_t YMODEM_SOH = 0x01;    /* 128字节数据包开始 */
uint8_t YMODEM_STX = 0x02;    /* 1024字节数据包开始 */
uint8_t YMODEM_EOT = 0x04;    /* 传输结束 */
uint8_t YMODEM_ACK = 0x06;    /* 确认 */
uint8_t YMODEM_NAK = 0x15;    /* 否定确认 */
uint8_t YMODEM_C = 0x43;      /* 请求数据包 */
uint8_t YMODEM_CAN = 0x18;    /* 取消传输 */
uint8_t YMODEM_NULL = 0x00;   /* 空字符 */
uint8_t YMODEM_XSHELL = 0x4F; /* XSHELL结束命令 */

/* 初始化接收缓冲区 */
void YMODEM_InitBuffer(CircularBuffer_t *p_sCircularBuffer_t)
{
    p_sCircularBuffer_t->head = 0;
    p_sCircularBuffer_t->tail = 0;
    memset(p_sCircularBuffer_t->data, 0, sizeof(p_sCircularBuffer_t->data));
}
/**
 * @brief 将数据压入接收缓冲区
 * @param data 指向要压入数据的缓冲区
 * @param size 要压入的字节数
 * @return 0表示成功，-1表示缓冲区溢出
 */
int PushCircularBuffer(CircularBuffer_t *p_sCircularBuffer_t, uint8_t *data, uint16_t size)
{
    // 检查缓冲区是否有足够空间
    uint16_t available = (UART_RX_BUFFER_SIZE - p_sCircularBuffer_t->tail + p_sCircularBuffer_t->head) % UART_RX_BUFFER_SIZE;
    if (available == 0)
        available = UART_RX_BUFFER_SIZE; // 缓冲区为空时

    if (size > available)
    {
        return -1; // 缓冲区溢出
    }

    // 处理数据可能跨越缓冲区末尾的情况
    if (p_sCircularBuffer_t->tail + size <= UART_RX_BUFFER_SIZE)
    {
        // 数据不跨越缓冲区末尾
        memcpy(p_sCircularBuffer_t->data + p_sCircularBuffer_t->tail, data, size);
    }
    else
    {
        // 数据跨越缓冲区末尾，分两次复制
        uint16_t first_part_size = UART_RX_BUFFER_SIZE - p_sCircularBuffer_t->tail;
        memcpy(p_sCircularBuffer_t->data + p_sCircularBuffer_t->tail, data, first_part_size);
        memcpy(p_sCircularBuffer_t->data, data + first_part_size, size - first_part_size);
    }
    // p_sCircularBuffer_t->size += size;
    //  更新tail指针
    p_sCircularBuffer_t->tail = (p_sCircularBuffer_t->tail + size) % UART_RX_BUFFER_SIZE;
    return 0;
}
/**
 * @brief 从接收缓冲区读取数据但不删除（只读不出队）
 * @param data 指向存储读取数据的缓冲区
 * @param size 要读取的字节数
 * @return 实际读取的字节数，-1表示缓冲区中数据不足
 */
int ReadCircularBuffer(CircularBuffer_t *p_sCircularBuffer_t, uint8_t *data, uint16_t size)
{
    uint16_t used_size = (p_sCircularBuffer_t->tail - p_sCircularBuffer_t->head + UART_RX_BUFFER_SIZE) % UART_RX_BUFFER_SIZE;

    if (size > used_size)
    {
        return -1; // 缓冲区中数据不足
    }

    // 处理数据可能跨越缓冲区末尾的情况
    if (p_sCircularBuffer_t->head + size <= UART_RX_BUFFER_SIZE)
    {
        // 数据不跨越缓冲区末尾
        memcpy(data, p_sCircularBuffer_t->data + p_sCircularBuffer_t->head, size);
    }
    else
    {
        // 数据跨越缓冲区末尾，分两次复制
        uint16_t first_part_size = UART_RX_BUFFER_SIZE - p_sCircularBuffer_t->head;
        memcpy(data, p_sCircularBuffer_t->data + p_sCircularBuffer_t->head, first_part_size);
        memcpy(data + first_part_size, p_sCircularBuffer_t->data, size - first_part_size);
    }
    // p_sCircularBuffer_t->size -= size;
    //  更新head指针
    p_sCircularBuffer_t->head = (p_sCircularBuffer_t->head + size) % UART_RX_BUFFER_SIZE;
    return 0; // 读取成功
}
int GetCircularBufferByIndex(CircularBuffer_t *p_sCircularBuffer_t, uint16_t index)
{
    return p_sCircularBuffer_t->data[(p_sCircularBuffer_t->head + index) % UART_RX_BUFFER_SIZE];
}
/**
 * @brief 从接收缓冲区弹出数据（移动指针，不复制数据）
 * @param data 未使用参数，可以设置为NULL
 * @param size 要弹出的字节数
 * @return 0表示成功，-1表示缓冲区中数据不足
 */
int PopCircularBuffer(CircularBuffer_t *p_sCircularBuffer_t, uint16_t size)
{
    uint16_t used_size = (p_sCircularBuffer_t->tail - p_sCircularBuffer_t->head + UART_RX_BUFFER_SIZE) % UART_RX_BUFFER_SIZE;

    if (size > used_size)
    {
        return -1; // 缓冲区中数据不足
    }
    // p_sCircularBuffer_t->size -= size;
    //  只移动指针，不复制数据
    p_sCircularBuffer_t->head = (p_sCircularBuffer_t->head + size) % UART_RX_BUFFER_SIZE;
    return 0;
}
int GetCircularBufferSize(CircularBuffer_t *p_sCircularBuffer_t)
{
    int offset = p_sCircularBuffer_t->tail - p_sCircularBuffer_t->head;
    return (offset >= 0) ? offset : offset + UART_RX_BUFFER_SIZE;
}

/* USER CODE END 0 */

/* 计算CRC16校验 */
uint16_t YMODEM_CalculateCRC16(uint8_t *data, uint16_t size)
{
    uint16_t crc = 0;
    uint16_t i, j;

    for (i = 0; i < size; i++)
    {
        crc ^= (uint16_t)(data[i] << 8);
        for (j = 0; j < 8; j++)
        {
            if (crc & 0x8000)
            {
                crc = (crc << 1) ^ CRC16_POLYNOMIAL;
            }
            else
            {
                crc <<= 1;
            }
        }
    }

    return crc;
}
/* 接收缓冲区 */
CircularBuffer_t ymodem_rx_buffer; // 包类型 + 包号 + 反包号 + 数据 + CRC
/* 处理接收到的字符 */
void YMODEM_ProcessReceivedData(uint8_t *data, uint16_t size)
{
    //    printf("Received data: [%d][%d][%d][%d]\n",uart_rx_length,GetCircularBufferSize(&ymodem_rx_buffer),ymodem_rx_buffer.head,ymodem_rx_buffer.tail);
    int iRet = PushCircularBuffer(&ymodem_rx_buffer, data, size);
    if (iRet != 0)
    {
        printf("PushCircularBuffer error, size: %d\r\n", size);
        return;
    }
    uart_rx_flag = 1;
}
// 写入OTA标志（这里需要根据实际的meta结构实现）

#define OTA_MAGIC 0xB00710AD // 魔术字

// 计算CRC32（这里使用简单的实现）
uint32_t crc32_calculate(uint32_t base, uint32_t size)
{
    uint32_t c = 0xFFFFFFFF;
    for (uint32_t i = 0; i < size; i++)
    {
        c ^= *(uint8_t *)(base + i);
        for (int j = 0; j < 8; j++)
        {
            c = (c & 1) ? (0xEDB88320u ^ (c >> 1)) : (c >> 1);
        }
    }
    return c ^ 0xFFFFFFFF;
}

#define BEGIN_WAITING_ENTER_UPGRADE 3 // N*1S 等待N秒内要检测到升级指令
#define MAX_DELAY_C_RES 500           // N*1S 等待N秒之内要开始接受文件

/* USER CODE BEGIN 1 */
/* YMODEM状态机处理函数 */
void YMODEM_Process(void)
{
    uint32_t delay_time = HAL_GetTick() + 1000;
    uint32_t delay_count = 0;
    uint32_t written_bytes = 0;

    ymodem_state_t ymodem_state = YMODEM_STATE_IDLE; // 升级状态机
    uint8_t current_packet_number = 0;               /* 当前包编号 */

    char file_name[256] = {0};                     /* 文件名 */
    uint32_t file_size = 0;                        /* 文件大小 */
    uint32_t firmware_write_addr = OTA_START_ADDR; /* 固件写入地址 */
    uint8_t ymodem_rx_buffer_[UART_RX_BUFFER_SIZE];

    memset(file_name, 0, sizeof(file_name));
    YMODEM_InitBuffer(&ymodem_rx_buffer);
    while (1)
    {
        switch (ymodem_state)
        {
        case YMODEM_STATE_IDLE:
            if (delay_time <= HAL_GetTick())
            {
                // printf("no response!, GetTick: %d[%d]\r\n", delay_time, HAL_GetTick());
                delay_time = HAL_GetTick() + 1000;
                if (delay_count++ >= BEGIN_WAITING_ENTER_UPGRADE)
                {
                    delay_count = 0;
                    // printf("Skip upgrade mode!\r\n");
                    ymodem_state = YMODEM_STATE_SKIP;
                    break; // 3秒无响应，退出升级模式
                }
            }

            if (uart_rx_flag)
            {
                uart_rx_flag = 0;
                // 检查是否接收到回车换行
                for (uint16_t i = 0; i < GetCircularBufferSize(&ymodem_rx_buffer); i++)
                {
                    if (GetCircularBufferByIndex(&ymodem_rx_buffer, i) == 0x0D)
                    {
                        printf("bootloader build time[%s][%s]\r\n", __DATE__, __TIME__);
                        printf("begine enter upgrade mode!\r\n");
                        printf("please begin send firmware file by ymodem !\r\n");
                        delay_time = HAL_GetTick() + 1000;
                        PopCircularBuffer(&ymodem_rx_buffer, GetCircularBufferSize(&ymodem_rx_buffer)); // 清空接收缓冲区
                        ymodem_state = YMODEM_STATE_SEND_C;
                        break;
                    }
                }
            }
            break;
        case YMODEM_STATE_SEND_C:
            if (delay_time <= HAL_GetTick())
            {
                // HAL_UART_Transmit(&huart1, (uint8_t *)&YMODEM_NAK, 1, 100);
                HAL_UART_Transmit(&huart1, (uint8_t *)&YMODEM_C, 1, 100);
                delay_count++;
                delay_time = HAL_GetTick() + 1000;
                if (delay_count++ >= MAX_DELAY_C_RES) // 延时25S判断是否进入
                {
                    printf("send YMODEM_C but no response!\r\n");
                    ymodem_state = YMODEM_STATE_ERROR; // 10秒无响应，退出升级模式
                }
            }
            if (uart_rx_flag)
            {
                // 如果只收到一字节，且为
                //  第一次收到EOT后发送了NAK，现在等待第二次EOT
                if (GetCircularBufferSize(&ymodem_rx_buffer) == 1 && GetCircularBufferByIndex(&ymodem_rx_buffer, 0) == YMODEM_EOT)
                {
                    uart_rx_flag = 0; // 会一直接收到0x0D
                    printf("Get[%d] [%d], size: %d\r\n", __LINE__, GetCircularBufferByIndex(&ymodem_rx_buffer, 0), GetCircularBufferSize(&ymodem_rx_buffer));
                    PopCircularBuffer(&ymodem_rx_buffer, GetCircularBufferSize(&ymodem_rx_buffer)); // 清空接收缓冲区
                    // 第二次收到EOT，发送ACK
                    ymodem_state = YMODEM_STATE_WAIT_EOT;
                    delay_time = HAL_GetTick() + 1000;
                    delay_count = 0;
                    HAL_UART_Transmit(&huart1, (uint8_t *)&YMODEM_ACK, 1, 100);
                }
                for (uint16_t i = 0; i < GetCircularBufferSize(&ymodem_rx_buffer); i++)
                {
                    // 检查是否接收完一个数据包
                    if ((GetCircularBufferByIndex(&ymodem_rx_buffer, i) == YMODEM_SOH && GetCircularBufferSize(&ymodem_rx_buffer) >= YMODEM_PACKET_SIZE_128 + 5) ||
                        (GetCircularBufferByIndex(&ymodem_rx_buffer, i) == YMODEM_STX && GetCircularBufferSize(&ymodem_rx_buffer) >= YMODEM_PACKET_SIZE_1024 + 5))
                    {
                        // indexbuff = i;
                        PopCircularBuffer(&ymodem_rx_buffer, i); // 弹出已处理的字节
                        // printf("Get YMODEM_SOH or YMODEM_STX!\r\n");
                        ymodem_state = YMODEM_STATE_VERIFY_PACKET;
                        break;
                    }
                    else
                    {
                        uart_rx_flag = 0; // 会一直接收到0x0D
                    }
                }
            }
            break;
        case YMODEM_STATE_VERIFY_PACKET: // 验证后续包
            // if (uart_rx_flag)
            {

                ReadCircularBuffer(&ymodem_rx_buffer, ymodem_rx_buffer_, GetCircularBufferSize(&ymodem_rx_buffer));
                // 验证包编号和CRC
                uint8_t packet_number = ymodem_rx_buffer_[1];
                uint8_t packet_number_complement = ymodem_rx_buffer_[2];

                // 检查包编号是否正确
                if ((packet_number ^ packet_number_complement) != 0xFF)
                {
                    printf("packet_number error! packet_number: %d, packet_number_complement: %d\r\n", packet_number, packet_number_complement);
                    // 包编号错误，发送NAK
                    HAL_UART_Transmit(&huart1, (uint8_t *)&YMODEM_NAK, 1, 100);
                    ymodem_state = YMODEM_STATE_ERROR;
                    continue;
                }
                else
                {
                    // 检查包编号是否连续
                    if (packet_number != current_packet_number)
                    {
                        // 包编号不连续，发送NAK
                        printf("packet_number not continuous! packet_number: %d, current_packet_number: %d\r\n", packet_number, current_packet_number);
                        ymodem_state = YMODEM_STATE_ERROR;
                        continue;
                    }
                    else
                    {
                        // 验证CRC
                        uint16_t data_size = (ymodem_rx_buffer_[0] == YMODEM_SOH) ? YMODEM_PACKET_SIZE_128 : YMODEM_PACKET_SIZE_1024;
                        uint16_t received_crc = ((uint16_t)ymodem_rx_buffer_[data_size + 3] << 8) | ymodem_rx_buffer_[data_size + 4];
                        uint16_t calculated_crc = YMODEM_CalculateCRC16(&ymodem_rx_buffer_[3], data_size);

                        if (received_crc == calculated_crc)
                        {

                            // CRC正确，处理数据
                            if (current_packet_number == 0)
                            {
                                // 第一包数据，解析文件名和文件大小
                                char *token = (char *)&ymodem_rx_buffer_[3];
                                strcpy(file_name, token); // 获取文件名
                                file_size = atoi(token + strlen(file_name) + 1);
                                printf("Receiving file: %s, size: %d bytes\r\n", file_name, file_size);

                                // 擦除OTA区域
                                HAL_FLASH_Unlock();
                                FLASH_EraseInitTypeDef erase;
                                uint32_t page_error = 0;

                                erase.TypeErase = FLASH_TYPEERASE_PAGES;
                                erase.PageAddress = OTA_START_ADDR;
                                erase.NbPages = (OTA_END_ADDR - OTA_START_ADDR) / FLASH_PAGE_SIZE;

                                if (HAL_FLASHEx_Erase(&erase, &page_error) == HAL_OK)
                                {
                                    printf("OTA area erased successfully\r\n");
                                }
                                else
                                {
                                    printf("Failed to erase OTA area\r\n");
                                    HAL_FLASH_Lock();
                                    ymodem_state = YMODEM_STATE_ERROR;
                                    break;
                                }
                                HAL_FLASH_Lock();
                                PopCircularBuffer(&ymodem_rx_buffer, GetCircularBufferSize(&ymodem_rx_buffer)); // 清空缓存区
                            }
                            else
                            {
                                // 后续数据包，写入FLASH
                                uint32_t data_size_to_write = data_size;

                                // 写入数据到FLASH
                                HAL_FLASH_Unlock();

                                for (uint16_t j = 0; j < data_size; j += 2)
                                {
                                    uint16_t halfword;

                                    uint8_t b1 = ymodem_rx_buffer_[j + 3];
                                    uint8_t b2 = (j + 1 < data_size) ? ymodem_rx_buffer_[j + 4] : 0xFF;
                                    halfword = (uint16_t)(b1 | (b2 << 8));

                                    if (firmware_write_addr + j < OTA_END_ADDR)
                                    {
                                        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, firmware_write_addr + j, halfword) != HAL_OK)
                                        {
                                            printf("Failed to write to FLASH at address 0x%08X\r\n", firmware_write_addr + j);
                                            HAL_FLASH_Lock();
                                            ymodem_state = YMODEM_STATE_ERROR;
                                            break;
                                        }
                                        written_bytes += 2;
                                    }
                                }

                                HAL_FLASH_Lock();

                                if (ymodem_state != YMODEM_STATE_ERROR)
                                {
                                    firmware_write_addr += data_size;
                                    // printf("Written %d bytes, total: %ld bytes\r\n", data_size, firmware_write_addr - OTA_START_ADDR);
                                }

                                PopCircularBuffer(&ymodem_rx_buffer, GetCircularBufferSize(&ymodem_rx_buffer)); // 清空缓存区
                            }
                            // 更新包编号
                            current_packet_number++;
                            if (current_packet_number > 255)
                            {
                                current_packet_number = 0;
                            }
                            // 继续等待下一个数据包
                            ymodem_state = YMODEM_STATE_SEND_C;
                            HAL_UART_Transmit(&huart1, (uint8_t *)&YMODEM_ACK, 1, 100);
                        }
                        else
                        {
                            printf("CRC error, packet number: %d\r\n", current_packet_number);
                            // CRC错误，发送NAK
                            HAL_UART_Transmit(&huart1, (uint8_t *)&YMODEM_NAK, 1, 100);
                            ymodem_state = YMODEM_STATE_ERROR;
                        }
                    }
                } //
            }
            break;
        case YMODEM_STATE_WAIT_EOT:
            if (uart_rx_flag)
            {
                uart_rx_flag = 0;
                printf("Get[%d] [%d], size: %d\r\n", __LINE__, GetCircularBufferByIndex(&ymodem_rx_buffer, 0), GetCircularBufferSize(&ymodem_rx_buffer));
                if (GetCircularBufferByIndex(&ymodem_rx_buffer, 0) == YMODEM_EOT)
                {                                                                                   // 会一直接收到0x0D
                    PopCircularBuffer(&ymodem_rx_buffer, GetCircularBufferSize(&ymodem_rx_buffer)); // 清空接收缓冲区
                    // 第二次收到EOT，发送ACK
                    ymodem_state = YMODEM_STATE_SEND_NAK_EOT;
                    delay_time = HAL_GetTick() + 1000;
                    delay_count = 0;
                    HAL_UART_Transmit(&huart1, (uint8_t *)&YMODEM_C, 1, 100);
                }
            }
            if (delay_time <= HAL_GetTick())
            {
                delay_time = HAL_GetTick() + 1000;
                printf("YMODEM_STATE_WAIT_EOT timeout!\r\n");
                ymodem_state = YMODEM_STATE_ERROR;
            }
            break;
        case YMODEM_STATE_SEND_NAK_EOT:
            if (uart_rx_flag)
            {
                uart_rx_flag = 0;
                printf("Get[%d] [%d], size: %d\r\n", __LINE__, GetCircularBufferByIndex(&ymodem_rx_buffer, 0), GetCircularBufferSize(&ymodem_rx_buffer));
                if (GetCircularBufferByIndex(&ymodem_rx_buffer, 0) == YMODEM_SOH)
                {                                                                                   // 会一直接收到0x0D
                    PopCircularBuffer(&ymodem_rx_buffer, GetCircularBufferSize(&ymodem_rx_buffer)); // 清空接收缓冲区
                    // 第二次收到EOT，发送ACK
                    ymodem_state = YMODEM_STATE_FINISH;
                    delay_time = HAL_GetTick() + 1000;
                    delay_count = 0;
                    HAL_UART_Transmit(&huart1, (uint8_t *)&YMODEM_XSHELL, 1, 100);
                }
            }
            if (delay_time <= HAL_GetTick())
            {
                delay_time = HAL_GetTick() + 1000;
                printf("YMODEM_STATE_FINISH timeout!\r\n");
                ymodem_state = YMODEM_STATE_ERROR;
            }
            break;
        case YMODEM_STATE_FINISH:
            HAL_UART_Transmit(&huart1, (uint8_t *)&YMODEM_XSHELL, 1, 100);
            // 传输完成
            printf("File transfer completed\r\n");
            break;
        case YMODEM_STATE_ERROR:
            // 错误状态
            printf("YMODEM error\r\n");
            ymodem_state = YMODEM_STATE_IDLE;
            break;

        default:
            break;
        }

        // 如果状态已经变为错误或完成，退出循环
        if (ymodem_state == YMODEM_STATE_ERROR)
        {
            printf("upgrade process YMODEM_STATE_ERROR!\n\r");
            ymodem_state = YMODEM_STATE_IDLE;
            break;
        }
        // 如果状态已经变为错误或完成，退出循环
        else if (ymodem_state == YMODEM_STATE_FINISH)
        {
            printf("received [%s]-[%d]\r\n", file_name, file_size);
            printf("upgrade process YMODEM_STATE_FINISH!\n\r");
            ymodem_state = YMODEM_STATE_IDLE;
            break;
        }
        else if (ymodem_state == YMODEM_STATE_SKIP)
        {
            // printf("upgrade process YMODEM_STATE_SKIP!\n\r");
            ymodem_state = YMODEM_STATE_IDLE;
            break;
        }
    }
    // }

    // // 如果接收完成，写入OTA标志并重启
    // if (ymodel_received)
    // {
    //     printf("Writing OTA flag...\r\n");

    //     // 写入标志
    //     ota_flag_t flag;
    //     flag.magic = OTA_MAGIC;
    //     flag.fw_size = firmware_write_addr - OTA_START_ADDR;
    //     flag.fw_crc32 = crc32_calculate(OTA_START_ADDR, flag.fw_size);
    //     flag.committed = 0x5AA55AA5;

    //     // 擦除标志页
    //     HAL_FLASH_Unlock();
    //     FLASH_EraseInitTypeDef erase;
    //     uint32_t page_error = 0;

    //     erase.TypeErase = FLASH_TYPEERASE_PAGES;
    //     erase.PageAddress = Flage_PAGE_ADDR;
    //     erase.NbPages = 1;

    //     if (HAL_FLASHEx_Erase(&erase, &page_error) == HAL_OK)
    //     {
    //         // 写入标志
    //         uint32_t *flag_ptr = (uint32_t *)&flag;
    //         for (uint32_t i = 0; i < sizeof(ota_flag_t) / 4; i++)
    //         {
    //             HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Flage_PAGE_ADDR + i * 4, flag_ptr[i]);
    //         }
    //         printf("OTA flag written successfully\r\n");
    //     }
    //     else
    //     {
    //         printf("Failed to erase OTA flag page\r\n");
    //     }

    //     HAL_FLASH_Lock();
    // }
}
/* USER CODE END 1 */
